<template>
  <div class="container" ref="containerRef">
    <!-- 视频和姿态检测画布 (全屏显示) -->
    <div class="video-container" :style="{ opacity: videoOpacity / 100 }">
      <video ref="videoRef" autoplay playsinline class="camera-feed"></video>
      <canvas ref="canvasRef" class="detection-overlay"></canvas>
    </div>
    
    <!-- 控制面板 -->
    <div class="controls">
      <h3>3D 跳绳控制器</h3>
      <button @click="toggleDetection" :disabled="isLoading">{{ isDetecting ? '停止检测' : '开始检测' }}</button>
      <button @click="resetDetection" :disabled="!isModelLoaded && !isDetecting">重置</button>
      
      <div class="video-controls">
        <label>视频透明度: {{ videoOpacity }}%</label>
        <input 
          type="range" 
          min="30" 
          max="100" 
          v-model="videoOpacity" 
          class="opacity-slider"
        >
      </div>
      
      <div class="status-display">
        <p>状态: <span :class="statusClass">{{ statusText }}</span></p>
        <p v-if="isLoading">加载进度: {{ loadingProgress }}%</p>
        <p>跳跃计数: <strong>{{ jumpCount }}</strong> 次</p>
        <p>成功率: <strong>{{ successRate.toFixed(1) }}%</strong></p>
        <p>当前高度: <strong>{{ jumpHeight.toFixed(1) }}cm</strong></p>
      </div>
    </div>
    
    <!-- 错误提示 -->
    <div class="error-message" v-if="errorMessage">{{ errorMessage }}</div>
    
    <!-- 使用说明 -->
    <div class="instructions">
      <h4>使用说明</h4>
      <ul>
        <li>确保已授予摄像头权限</li>
        <li>站在摄像头前，确保全身可见</li>
        <li>点击"开始检测"启动摄像头和检测</li>
        <li>上下跳跃来控制跳绳摆动</li>
        <li>调整视频透明度，使您和跳绳同时清晰可见</li>
      </ul>
    </div>
    
    <!-- 跳跃力度指示 -->
    <div class="jump-indicator" v-if="isDetecting">
      <div class="indicator-label">跳跃力度</div>
      <div class="indicator-bar" :style="{ height: `${jumpHeightPercent}%` }"></div>
    </div>
    
    <!-- 加载中遮罩 -->
    <div class="loading-overlay" v-if="isLoading">
      <div class="loading-spinner"></div>
      <div class="loading-text">{{ statusText }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed, watch, nextTick } from 'vue'
import * as THREE from 'three'
import * as tf from '@tensorflow/tfjs'
import * as posedetection from '@tensorflow-models/pose-detection'
import '@tensorflow/tfjs-backend-webgl'

// DOM引用
const containerRef = ref<HTMLElement | null>(null)
const videoRef = ref<HTMLVideoElement | null>(null)
const canvasRef = ref<HTMLCanvasElement | null>(null)

// 状态变量
const isDetecting = ref(false)
const isLoading = ref(false)
const loadingProgress = ref(0)
const statusText = ref('就绪')
const statusClass = ref('status-inactive')
const errorMessage = ref('')
const jumpCount = ref(0)
const successCount = ref(0)
const jumpHeight = ref(0)
const jumpHeightPercent = ref(0)
const isModelLoaded = ref(false)
const isCameraReady = ref(false)
const videoOpacity = ref(70) // 视频透明度，默认70%

// 跳跃检测参数
const JUMP_THRESHOLD = 30 // 跳跃最小高度阈值 (厘米)
const MIN_CONFIDENCE = 0.5 // 关键点检测最小置信度
const SMOOTHING_FACTOR = 0.2 // 平滑因子
const JUMP_COOLDOWN = 500 // 跳跃检测冷却时间 (毫秒)

// 姿态跟踪变量
let hipYHistory: number[] = []
let jumpStartY = 0
let isJumpInProgress = false
let lastJumpTime = 0
let initialHipY = 0
let hipY = 0
let previousHipY = 0
let velocity = 0
let jumpPeakY = 0

// Three.js对象
let scene: THREE.Scene | null = null
let camera: THREE.PerspectiveCamera | null = null
let renderer: THREE.WebGLRenderer | null = null
let rope: THREE.Mesh | null = null
let leftHandle: THREE.Mesh | null = null
let rightHandle: THREE.Mesh | null = null
let ropeGroup: THREE.Group | null = null
let animationId: number | null = null
let detectionId: number | null = null
let swingAngle = 0
let targetSwingAngle = 0

// TensorFlow.js姿态检测
let detector: posedetection.PoseDetector | null = null
let videoWidth = 0
let videoHeight = 0
let pixelsPerCm = 0 // 像素到厘米的转换比例

// 更新状态文本和样式
const updateStatus = (text: string, newStatusClass: string) => {
  statusText.value = text
  statusClass.value = newStatusClass
}

// 设置摄像头（全屏）
const setupCamera = async (): Promise<boolean> => {
  try {
    updateStatus('正在访问摄像头...', 'status-loading')
    
    // 检查摄像头权限
    const mediaDevices = navigator.mediaDevices
    if (!mediaDevices || !mediaDevices.getUserMedia) {
      throw new Error('您的浏览器不支持摄像头访问，请使用现代浏览器')
    }
    
    const video = videoRef.value!
    
    // 先尝试停止任何已存在的流
    if (video.srcObject) {
      const stream = video.srcObject as MediaStream
      stream.getTracks().forEach(track => track.stop())
    }
    
    // 请求摄像头权限，使用尽可能高的分辨率
    const stream = await mediaDevices.getUserMedia({
      video: { 
        width: { ideal: window.innerWidth }, 
        height: { ideal: window.innerHeight },
        facingMode: 'user'
      },
      audio: false
    })
    
    video.srcObject = stream
    
    // 等待视频元数据加载完成
    await new Promise((resolve, reject) => {
      video.onloadedmetadata = () => resolve(null)
      video.onerror = (e) => reject(new Error(`视频加载失败: ${e}`))
    })
    
    // 播放视频
    await video.play()
    
    // 设置视频和画布尺寸以适应全屏
    videoWidth = video.videoWidth
    videoHeight = video.videoHeight
    
    // 等待下一帧确保DOM已更新
    await nextTick()
    
    // 调整视频尺寸以适应屏幕
    resizeVideo()
    
    isCameraReady.value = true
    updateStatus('摄像头已就绪，请站到屏幕中央', 'status-ready')
    return true
  } catch (error) {
    console.error('摄像头初始化失败:', error)
    
    // 详细的错误信息处理
    if (error instanceof DOMException) {
      if (error.name === 'NotAllowedError') {
        errorMessage.value = '摄像头访问被拒绝。请在浏览器设置中启用摄像头权限，然后点击"重置"重试。'
      } else if (error.name === 'NotFoundError') {
        errorMessage.value = '未找到摄像头设备。请确保您的设备有摄像头并已正确连接。'
      } else if (error.name === 'NotReadableError') {
        errorMessage.value = '摄像头正被其他应用占用。请关闭占用摄像头的应用，然后点击"重置"重试。'
      } else {
        errorMessage.value = `摄像头错误: ${error.message}`
      }
    } else {
      errorMessage.value = `初始化摄像头失败: ${error instanceof Error ? error.message : String(error)}`
    }
    
    updateStatus('摄像头初始化失败', 'status-error')
    return false
  }
}

// 调整视频尺寸以适应屏幕
const resizeVideo = () => {
  if (!videoRef.value || !canvasRef.value) return
  
  const container = containerRef.value!
  const containerWidth = container.clientWidth
  const containerHeight = container.clientHeight
  
  // 计算视频的缩放比例，保持宽高比
  const videoRatio = videoWidth / videoHeight
  const containerRatio = containerWidth / containerHeight
  
  let newWidth, newHeight
  
  if (containerRatio > videoRatio) {
    // 容器比视频宽，以高度为基准缩放
    newHeight = containerHeight
    newWidth = newHeight * videoRatio
  } else {
    // 容器比视频高，以宽度为基准缩放
    newWidth = containerWidth
    newHeight = newWidth / videoRatio
  }
  
  // 设置视频和画布尺寸
  const video = videoRef.value
  const canvas = canvasRef.value
  
  video.style.width = `${newWidth}px`
  video.style.height = `${newHeight}px`
  video.style.left = `${(containerWidth - newWidth) / 2}px`
  video.style.top = `${(containerHeight - newHeight) / 2}px`
  
  canvas.width = videoWidth
  canvas.height = videoHeight
  canvas.style.width = `${newWidth}px`
  canvas.style.height = `${newHeight}px`
  canvas.style.left = `${(containerWidth - newWidth) / 2}px`
  canvas.style.top = `${(containerHeight - newHeight) / 2}px`
}

// 加载姿态检测模型
const loadModel = async (): Promise<boolean> => {
  try {
    updateStatus('正在加载姿态检测模型...', 'status-loading')
    isLoading.value = true
    loadingProgress.value = 20
    
    // 检查TensorFlow后端
    if (!tf.getBackend()) {
      updateStatus('正在初始化TensorFlow...', 'status-loading')
      await tf.setBackend('webgl')
      loadingProgress.value = 40
    }
    
    await tf.ready()
    loadingProgress.value = 60
    
    // 使用MoveNet模型，检测全身关键点
    detector = await posedetection.createDetector(
      posedetection.SupportedModels.MoveNet,
      { 
        modelType: posedetection.movenet.modelType.MULTIPOSE_LIGHTNING,
        enableTracking: true
      }
    )
    
    loadingProgress.value = 100
    isModelLoaded.value = true
    isLoading.value = false
    updateStatus('模型加载完成，准备就绪', 'status-ready')
    return true
  } catch (error) {
    console.error('模型加载失败:', error)
    isLoading.value = false
    errorMessage.value = `模型加载失败: ${error instanceof Error ? error.message : String(error)}。请检查网络连接，然后点击"重置"重试。`
    updateStatus('模型加载失败', 'status-error')
    return false
  }
}

// 初始化Three.js场景
const initScene = () => {
  if (!containerRef.value) return
  
  // 初始化场景、相机和渲染器
  scene = new THREE.Scene()
  camera = new THREE.PerspectiveCamera(
    85, 
    window.innerWidth / window.innerHeight, 
    0.1, 
    1000
  )
  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }) // 使用透明背景
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setClearColor(0x000000, 0) // 完全透明背景
  containerRef.value.appendChild(renderer.domElement)
  
  // 创建绳子材质 - 使用明亮的蓝色，增加发光效果
  const ropeMaterial = new THREE.MeshPhongMaterial({
    color: 0x007aff,
    shininess: 150,
    specular: 0xffffff,
    emissive: 0x003366,
    emissiveIntensity: 0.3
  })
  
  // 创建绳子
  const ropeGeometry = new THREE.TubeGeometry(
    new THREE.CatmullRomCurve3([
      new THREE.Vector3(-10, 0, 0),
      new THREE.Vector3(0, 4.3, 0),
      new THREE.Vector3(10, 0, 0),
    ]),
    64, 0.08, 8, false
  )
  rope = new THREE.Mesh(ropeGeometry, ropeMaterial)
  
  // 创建黑色手柄材质，增加反光
  const handleMaterial = new THREE.MeshPhongMaterial({
    color: 0x333333,
    shininess: 100,
    specular: 0xaaaaaa,
  })
  
  // 创建手柄圆柱体
  const handleGeometry = new THREE.CylinderGeometry(0.08, 0.08, 0.8, 32)
  
  // 左手柄
  leftHandle = new THREE.Mesh(handleGeometry, handleMaterial)
  leftHandle.position.set(-10, 0.8, 0)
  
  // 右手柄
  rightHandle = new THREE.Mesh(handleGeometry, handleMaterial)
  rightHandle.position.set(10, 0.8, 0)
  
  // 添加更强的灯光以提高可见度
  const ambientLight = new THREE.AmbientLight(0x606060)
  const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5)
  directionalLight.position.set(5, 5, 5)
  
  // 添加点光源，增强立体感
  const pointLight = new THREE.PointLight(0xffffff, 0.8)
  pointLight.position.set(-5, 5, 5)
  
  // 创建绳子组
  ropeGroup = new THREE.Group()
  ropeGroup.add(rope)
  ropeGroup.position.y = 0.8
  
  // 将所有对象添加到场景
  scene.add(ropeGroup)
  scene.add(leftHandle)
  scene.add(rightHandle)
  scene.add(ambientLight)
  scene.add(directionalLight)
  scene.add(pointLight)
  
  // 调整相机位置，优化视角
  camera.position.z = 7
  camera.position.y = 1.5
  
  // 添加窗口大小调整监听
  window.addEventListener('resize', handleResize)
}

// 窗口大小调整处理
const handleResize = () => {
  if (!camera || !renderer) return
  
  // 更新Three.js渲染器
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
  
  // 调整视频大小
  if (isCameraReady.value) {
    resizeVideo()
  }
}

// 动画循环
const animate = () => {
  animationId = requestAnimationFrame(animate)
  
  // 更新跳绳摆动角度（平滑过渡到目标角度）
  if (ropeGroup) {
    // 使用平滑阻尼算法实现自然摆动
    swingAngle += (targetSwingAngle - swingAngle) * 0.15
    ropeGroup.rotation.x = swingAngle
    
    // 添加一些自然阻尼，使摆动逐渐停止
    targetSwingAngle *= 0.97
  }
  
  renderer?.render(scene!, camera!)
}

// 安全获取关键点的辅助函数
const getKeypoint = (keypoints: posedetection.Keypoint[], name: string): posedetection.Keypoint | null => {
  try {
    const kp = keypoints.find(kp => kp.name === name)
    return kp || null
  } catch (error) {
    console.error(`获取关键点 ${name} 失败:`, error)
    return null
  }
}

// 处理姿态检测
const detectPose = async () => {
  if (!detector || !videoRef.value || !canvasRef.value || !isDetecting.value) return
  
  try {
    const poses = await detector.estimatePoses(videoRef.value)
    processPoses(poses)
  } catch (error) {
    console.error('姿态检测出错:', error)
    updateStatus(`检测出错: ${error instanceof Error ? error.message : String(error)}`, 'status-error')
    
    // 自动尝试恢复检测
    setTimeout(() => {
      if (isDetecting.value) {
        detectionId = requestAnimationFrame(detectPose)
      }
    }, 1000)
    
    return
  }
  
  // 继续检测循环
  if (isDetecting.value) {
    detectionId = requestAnimationFrame(detectPose)
  }
}

// 处理姿态数据
const processPoses = (poses: posedetection.Pose[]) => {
  try {
    const canvas = canvasRef.value!
    const ctx = canvas.getContext('2d')!
    
    // 清除画布
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    
    // 绘制姿态检测结果
    if (poses.length > 0) {
      // 取最可信的姿态（分数最高的）
      const pose = poses.sort((a, b) => (b.score || 0) - (a.score || 0))[0]
      
      // 绘制骨架和关键点
      drawSkeleton(pose, ctx)
      
      // 安全获取髋部关键点（使用辅助函数）
      const leftHip = getKeypoint(pose.keypoints, 'left_hip')
      const rightHip = getKeypoint(pose.keypoints, 'right_hip')
      
      // 检查关键点是否有效
      const leftHipScore = leftHip?.score ?? 0
      const rightHipScore = rightHip?.score ?? 0
      
      // 关键点存在性和置信度检查
      if (leftHip && rightHip && leftHipScore > MIN_CONFIDENCE && rightHipScore > MIN_CONFIDENCE) {
        // 清除错误消息
        errorMessage.value = ''
        
        // 计算髋部中点
        const hipYCurrent = (leftHip.y + rightHip.y) / 2
        
        // 初始化初始髋部位置（站立位置）
        if (initialHipY === 0) {
          initialHipY = hipYCurrent
          previousHipY = hipYCurrent
          hipY = hipYCurrent
          hipYHistory = Array(10).fill(hipYCurrent) // 初始化历史数组
          updateStatus('准备就绪，请开始跳跃', 'status-ready')
        } else {
          // 使用平滑滤波减少噪声
          hipY = hipY * (1 - SMOOTHING_FACTOR) + hipYCurrent * SMOOTHING_FACTOR
          
          // 维护最近10帧的髋部位置历史
          hipYHistory.push(hipY)
          if (hipYHistory.length > 10) hipYHistory.shift()
          
          // 计算垂直速度（像素/帧）
          velocity = previousHipY - hipY
          previousHipY = hipY
          
          // 检测跳跃动作
          detectJump(hipY)
        }
        
        // 绘制髋部点（调试用）
        drawHipPoint(ctx, hipY)
      } else {
        // 详细的缺失关键点信息
        const missingParts = []
        if (!leftHip || leftHipScore <= MIN_CONFIDENCE) missingParts.push('左髋部')
        if (!rightHip || rightHipScore <= MIN_CONFIDENCE) missingParts.push('右髋部')
        
        updateStatus(`请确保${missingParts.join('和')}可见，调整姿势或光线`, 'status-warning')
      }
    } else {
      updateStatus('未检测到人体，请站到摄像头前', 'status-warning')
    }
  } catch (error) {
    console.error('处理姿态数据出错:', error)
    updateStatus(`处理姿态数据出错: ${error instanceof Error ? error.message : String(error)}`, 'status-error')
  }
}

// 检测跳跃动作
const detectJump = (currentHipY: number) => {
  try {
    const currentTime = Date.now()
    
    // 跳跃冷却期，防止连续检测
    if (currentTime - lastJumpTime < JUMP_COOLDOWN) return
    
    // 计算当前高度相对于初始位置的变化（注意Y轴向下为正）
    const heightChange = (initialHipY - currentHipY) * pixelsPerCm
    
    // 更新跳跃高度显示
    jumpHeight.value = Math.max(0, heightChange)
    jumpHeightPercent.value = Math.min(100, (jumpHeight.value / 100) * 100) // 最大显示100%
    
    // 跳跃检测逻辑
    if (!isJumpInProgress) {
      // 检测跳跃开始（向上运动，速度超过阈值）
      if (velocity > 2 && heightChange > 3) { // 2像素/帧的速度，3cm高度变化
        isJumpInProgress = true
        jumpStartY = currentHipY
        jumpPeakY = currentHipY
        updateStatus('跳跃中...', 'status-detecting')
      }
    } else {
      // 记录跳跃最高点
      if (currentHipY < jumpPeakY) {
        jumpPeakY = currentHipY
      }
      
      // 检测跳跃结束（开始下落且速度超过阈值）
      if (velocity < -1.5) { // 下落速度超过阈值
        isJumpInProgress = false
        lastJumpTime = currentTime
        
        // 计算跳跃高度（从起跳点到最高点）
        const jumpHeightCm = (jumpStartY - jumpPeakY) * pixelsPerCm
        
        // 只有有效跳跃才计数（超过阈值）
        if (jumpHeightCm > JUMP_THRESHOLD) {
          jumpCount.value++
          
          // 根据跳跃高度设置跳绳摆动角度
          const maxAngle = Math.PI / 2.5 // 最大摆动角度
          const angle = (jumpHeightCm / 100) * maxAngle // 假设最大跳跃高度100cm
          targetSwingAngle = angle
          
          // 成功跳跃
          successCount.value++
          updateStatus('跳跃成功!', 'status-success')
        } else {
          updateStatus(`跳跃太矮 (${jumpHeightCm.toFixed(1)}cm)，至少需要${JUMP_THRESHOLD}cm`, 'status-warning')
        }
      }
    }
  } catch (error) {
    console.error('跳跃检测逻辑出错:', error)
    updateStatus(`处理跳跃时出错: ${error instanceof Error ? error.message : String(error)}`, 'status-error')
  }
}

// 绘制骨架（调试用）
const drawSkeleton = (pose: posedetection.Pose, ctx: CanvasRenderingContext2D) => {
  try {
    const keypoints = pose.keypoints.filter(kp => kp.score && kp.score > MIN_CONFIDENCE * 0.5)
    
    // 绘制关键点，增大尺寸提高可见度
    keypoints.forEach(kp => {
      ctx.beginPath()
      ctx.arc(kp.x, kp.y, 12, 0, 2 * Math.PI)
      ctx.fillStyle = getColorForKeypoint(kp.name!)
      ctx.fill()
      
      // 添加白色边框提高对比度
      ctx.strokeStyle = '#ffffff'
      ctx.lineWidth = 2
      ctx.stroke()
      
      // 标记髋部关键点
      if (kp.name === 'left_hip' || kp.name === 'right_hip') {
        ctx.strokeStyle = '#ff0000'
        ctx.lineWidth = 3
        ctx.beginPath()
        ctx.arc(kp.x, kp.y, 18, 0, 2 * Math.PI)
        ctx.stroke()
      }
    })
    
    // 绘制骨架连接线，加粗线条
    drawConnectors(ctx, keypoints, [[11, 12], [12, 24], [24, 23], [23, 11], [11, 13], [13, 15], [12, 14], [14, 16]])
  } catch (error) {
    console.error('绘制骨架出错:', error)
  }
}

// 根据关键点名称获取颜色
const getColorForKeypoint = (name: string): string => {
  const colors: Record<string, string> = {
    'nose': '#ff0000',
    'left_eye': '#00ff00',
    'right_eye': '#00ff00',
    'left_ear': '#0000ff',
    'right_ear': '#0000ff',
    'left_shoulder': '#ffff00',
    'right_shoulder': '#ffff00',
    'left_elbow': '#ff00ff',
    'right_elbow': '#ff00ff',
    'left_wrist': '#00ffff',
    'right_wrist': '#00ffff',
    'left_hip': '#ff9900',
    'right_hip': '#ff9900',
    'left_knee': '#9900ff',
    'right_knee': '#9900ff',
    'left_ankle': '#00ff99',
    'right_ankle': '#00ff99'
  }
  
  return colors[name] || '#ffffff'
}

// 绘制骨架连接线
const drawConnectors = (ctx: CanvasRenderingContext2D, keypoints: posedetection.Keypoint[], connections: number[][]) => {
  ctx.strokeStyle = '#cccccc'
  ctx.lineWidth = 4 // 加粗线条提高可见度
  
  connections.forEach(([startIdx, endIdx]) => {
    try {
      const startKp = keypoints[startIdx]
      const endKp = keypoints[endIdx]
      
      if (startKp && endKp && startKp.score && endKp.score && 
          startKp.score > MIN_CONFIDENCE * 0.5 && endKp.score > MIN_CONFIDENCE * 0.5) {
        ctx.beginPath()
        ctx.moveTo(startKp.x, startKp.y)
        ctx.lineTo(endKp.x, endKp.y)
        ctx.stroke()
      }
    } catch (error) {
      console.error(`绘制连接线 ${startIdx}-${endIdx} 出错:`, error)
    }
  })
}

// 绘制髋部点（调试用）
const drawHipPoint = (ctx: CanvasRenderingContext2D, y: number) => {
  ctx.beginPath()
  ctx.arc(canvasRef.value!.width / 2, y, 15, 0, 2 * Math.PI)
  ctx.fillStyle = 'red'
  ctx.fill()
  
  // 添加白色边框和脉动动画效果
  ctx.strokeStyle = 'white'
  ctx.lineWidth = 3
  ctx.stroke()
}

// 切换姿态检测状态
const toggleDetection = async () => {
  if (isDetecting.value) {
    // 停止检测
    if (detectionId) {
      cancelAnimationFrame(detectionId)
      detectionId = null
    }
    isDetecting.value = false
    updateStatus('检测已停止', 'status-stopped')
  } else {
    // 开始检测
    errorMessage.value = '' // 清除任何之前的错误消息
    
    if (!isModelLoaded.value) {
      // 显示加载状态
      isLoading.value = true
      loadingProgress.value = 0
      
      // 分步加载资源
      try {
        // 1. 加载模型 (50%进度)
        updateStatus('正在加载姿态检测模型...', 'status-loading')
        const modelLoaded = await loadModel()
        if (!modelLoaded) {
          isLoading.value = false
          return
        }
        loadingProgress.value = 50
        
        // 2. 设置摄像头 (50%进度)
        updateStatus('正在初始化摄像头...', 'status-loading')
        const cameraReady = await setupCamera()
        if (!cameraReady) {
          isLoading.value = false
          return
        }
        loadingProgress.value = 100
      } catch (error) {
        console.error('初始化失败:', error)
        updateStatus(`初始化失败: ${error instanceof Error ? error.message : String(error)}`, 'status-error')
        isLoading.value = false
        return
      }
      
      // 加载完成
      isLoading.value = false
    } else if (!isCameraReady.value) {
      // 如果模型已加载但摄像头未就绪，尝试初始化摄像头
      isLoading.value = true
      updateStatus('正在初始化摄像头...', 'status-loading')
      
      const cameraReady = await setupCamera()
      isLoading.value = false
      
      if (!cameraReady) {
        return
      }
    }
    
    // 重置跳跃计数和状态
    resetDetectionState()
    
    // 开始检测
    isDetecting.value = true
    updateStatus('开始检测，请站到屏幕中央并跳跃', 'status-detecting')
    detectionId = requestAnimationFrame(detectPose)
  }
}

// 重置检测状态（不重新加载模型和摄像头）
const resetDetectionState = () => {
  jumpCount.value = 0
  successCount.value = 0
  initialHipY = 0
  hipYHistory = []
  targetSwingAngle = 0
  swingAngle = 0
  errorMessage.value = ''
}

// 完全重置检测（包括重新加载模型和摄像头）
const resetDetection = async () => {
  // 停止当前检测
  if (isDetecting.value) {
    if (detectionId) {
      cancelAnimationFrame(detectionId)
      detectionId = null
    }
    isDetecting.value = false
  }
  
  // 重置状态
  resetDetectionState()
  isCameraReady.value = false
  
  // 如果已经加载了模型，释放资源
  if (detector) {
    detector.dispose()
    detector = null
    isModelLoaded.value = false
  }
  
  // 如果有视频流，停止它
  const video = videoRef.value
  if (video && video.srcObject) {
    const stream = video.srcObject as MediaStream
    stream.getTracks().forEach(track => track.stop())
    video.srcObject = null
  }
  
  // 更新状态
  updateStatus('已重置，请点击"开始检测"重新启动', 'status-inactive')
}

// 清理资源
const cleanup = () => {
  // 停止动画和检测循环
  if (animationId) {
    cancelAnimationFrame(animationId)
  }
  if (detectionId) {
    cancelAnimationFrame(detectionId)
  }
  
  // 释放视频流
  const video = videoRef.value
  if (video && video.srcObject) {
    const stream = video.srcObject as MediaStream
    stream.getTracks().forEach(track => track.stop())
    video.srcObject = null
  }
  
  // 释放Three.js资源
  if (renderer) {
    renderer.dispose()
  }
  
  // 释放TensorFlow资源
  if (detector) {
    detector.dispose()
  }
  tf.disposeVariables()
  tf.resetBackend()
  
  // 移除事件监听
  window.removeEventListener('resize', handleResize)
}

// 计算成功率
const successRate = computed(() => {
  return jumpCount.value > 0 ? (successCount.value / jumpCount.value) * 100 : 0
})

// 生命周期钩子
onMounted(() => {
  // 初始化Three.js场景
  initScene()
  animate()
  
  // 预检查浏览器兼容性
  if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
    errorMessage.value = '您的浏览器不支持摄像头API，请使用最新版Chrome、Firefox或Edge浏览器。'
    updateStatus('浏览器不兼容', 'status-error')
  } else {
    updateStatus('就绪，请点击"开始检测"', 'status-ready')
  }
  
  // 监听窗口大小变化
  window.addEventListener('resize', resizeVideo)
})

onBeforeUnmount(() => {
  cleanup()
  window.removeEventListener('resize', resizeVideo)
})

// 监听视频透明度变化，提供视觉反馈
watch(videoOpacity, (newVal) => {
  updateStatus(`视频透明度已调整为 ${newVal}%`, 'status-info')
  
  // 短暂显示后恢复原状态
  setTimeout(() => {
    if (isDetecting.value) {
      updateStatus('正在检测，请继续跳跃', 'status-detecting')
    } else if (isCameraReady.value) {
      updateStatus('就绪，请点击"开始检测"', 'status-ready')
    }
  }, 1500)
})
</script>

<style scoped>
.container {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

/* 视频容器样式 - 全屏显示 */
.video-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  transition: opacity 0.3s ease;
}

.camera-feed {
  position: absolute;
  object-fit: contain;
  background-color: #000;
}

.detection-overlay {
  position: absolute;
  pointer-events: none;
}

/* 控制面板样式 */
.controls {
  position: absolute;
  top: 20px;
  left: 20px;
  background: rgba(255, 255, 255, 0.95);
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  z-index: 10;
  min-width: 280px;
}

.controls h3 {
  margin: 0 0 10px 0;
  color: #333;
}

.controls button {
  background-color: #007aff;
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.2s;
  margin-right: 8px;
  margin-bottom: 12px;
}

.controls button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.controls button:hover:not(:disabled) {
  background-color: #0062cc;
}

/* 视频透明度控制 */
.video-controls {
  margin: 15px 0;
  padding: 10px;
  background-color: rgba(240, 240, 240, 0.8);
  border-radius: 4px;
}

.video-controls label {
  display: block;
  margin-bottom: 8px;
  color: #555;
  font-size: 14px;
}

.opacity-slider {
  width: 100%;
  accent-color: #007aff;
}

.status-display {
  font-size: 14px;
  color: #333;
}

.status-display p {
  margin: 4px 0;
}

/* 状态样式 */
.status-error {
  color: #ff3b30;
  font-weight: bold;
}

.status-detecting {
  color: #007aff;
  font-weight: bold;
}

.status-ready {
  color: #34c759;
  font-weight: bold;
}

.status-stopped {
  color: #ff9500;
  font-weight: bold;
}

.status-warning {
  color: #ffcc00;
  font-weight: bold;
}

.status-loading {
  color: #007aff;
  font-weight: bold;
}

.status-info {
  color: #007aff;
  font-weight: bold;
}

.status-inactive {
  color: #8e8e93;
}

/* 错误消息样式 */
.error-message {
  position: absolute;
  top: 200px;
  left: 20px;
  background: rgba(255, 59, 48, 0.9);
  color: white;
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  max-width: 400px;
  z-index: 10;
  font-weight: bold;
}

/* 使用说明样式 */
.instructions {
  position: absolute;
  bottom: 20px;
  left: 20px;
  background: rgba(255, 255, 255, 0.95);
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  max-width: 300px;
  z-index: 10;
}

.instructions h4 {
  margin: 0 0 10px 0;
  color: #333;
}

.instructions ul {
  margin: 0;
  padding-left: 20px;
}

.instructions li {
  margin-bottom: 8px;
  font-size: 14px;
  color: #555;
}

/* 跳跃力度指示样式 */
.jump-indicator {
  position: absolute;
  top: 50%;
  right: 20px;
  transform: translateY(-50%);
  width: 30px;
  height: 200px;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 15px;
  padding: 10px 0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 10;
}

.indicator-label {
  font-size: 12px;
  color: #333;
  margin-bottom: 5px;
  text-align: center;
}

.indicator-bar {
  width: 20px;
  background: linear-gradient(to top, #007aff, #34c759);
  border-radius: 10px;
  position: absolute;
  bottom: 10px;
  transition: height 0.1s ease-out;
}

/* 加载遮罩样式 */
.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 20;
}

.loading-spinner {
  width: 50px;
  height: 50px;
  border: 5px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  border-top-color: white;
  animation: spin 1s ease-in-out infinite;
}

.loading-text {
  color: white;
  font-size: 18px;
  margin-top: 20px;
  font-weight: bold;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}
</style>